/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.tencent.tendon.convert.json;

import com.tencent.tendon.convert.util.*;
import java.util.Arrays;

/**
 *
 * @author nbzhang
 */
public abstract class JsonReader implements Poolable {

    protected int position = -1;

    protected AnyArray stack;

    public final void offer(Object e) {
        if (stack == null) stack = JsonPool.pollAnyArray();
        stack.add(e);
    }

    @SuppressWarnings("unchecked")
    public final <T> T stackOf(int deep) {
        if (stack == null) return null;
        int index = stack.size() - deep;
        if (index < 0) return null;
        return (T) stack.get(index);
    }

    public final void poll() {
        if (stack != null) stack.poll();
    }

    public final int position() {
        return this.position;
    }

    @Override
    public void prepare() {
    }

    @Override
    public void release() {
        this.position = -1;
        if (stack != null) {
            JsonPool.offer(stack);
            this.stack = null;
        }
    }

    public void close() {
        this.release();
    }

    /**
     * 找到指定的属性值 例如: {id : 1, data : { name : 'a', items : [1,2,3]}} seek('data.items') 直接跳转到 [1,2,3];
     *
     * @param key
     */
    public final void seek(String key) {
        if (key == null || key.length() < 1) return;
        final String[] keys = key.split("\\.");
        readChar(); //读掉 { [
        for (int i = 0; i < keys.length; i++) {
            char[] item = keys[i].toCharArray();
            while (this.hasNext()) {
                char[] fields = readValue();
                checkColon();
                if (Arrays.equals(item, fields)) break;
                skipValue();
            }
        }

    }

    /**
     * 跳过属性的值
     */
    public final void skipValue() {
        final char ch = readChar();
        if (ch == '"' || ch == '\'') {
            back(ch);
            readString();
        } else if (ch == '{') {
            while (hasNext()) {
                this.readField(JsonDeHandle.NULL);
                this.checkColon();
                this.skipValue();
            }
        } else if (ch == '[') {
            while (hasNext()) {
                this.skipValue();
            }
        } else {
            char c;
            for (;;) {
                c = nextChar();
                if (c <= ' ') return;
                if (c == '}' || c == ']' || c == ',' || c == ':') {
                    back(c);
                    return;
                }
            }
        }
    }

    /**
     * 读取下一个字符， 不跳过空白字符
     *
     * @return
     */
    protected abstract char nextChar();

    /**
     * 跳过空白字符， 返回一个非空白字符
     *
     * @return
     */
    protected char readChar() {
        char c = nextChar();
        if (c > ' ') return c;
        for (;;) {
            c = nextChar();
            if (c > ' ') return c;
        }
    }

    /**
     * 回退最后读取的字符
     *
     * @return
     */
    protected abstract void back(char ch);

    /**
     * 判断下一个非空白字符是否为{
     *
     */
    public void checkObject() {
        if (readChar() != '{') throw new JsonException("a json object text must begin with '{' (position = " + position + ")");
    }

    /**
     * 判断下一个非空白字符是否为[
     */
    public boolean checkArray() {
        char ch = readChar();
        if (ch == '[') return true;
        if (ch == '{') return false;
        throw new JsonException("a json array text must begin with '[' (position = " + position + ")");
    }

    /**
     * 判断下一个非空白字符是否:
     */
    public void checkColon() {
        if (readChar() != ':') throw new JsonException("expected a ':' after a key (position = " + position + ")");
    }

    /**
     * 判断对象是否存在下一个属性或者数组是否存在下一个元素
     *
     * @return
     */
    public boolean hasNext() {
        char ch = readChar();
        if (ch == ',') return true;
        if (ch == '}' || ch == ']') return false;
        back(ch);
        return true;
    }

    /**
     * 读取字段名， 如果读取的字段名与给予的相同， 则返回null
     *
     * @param expectedfield
     * @return
     */
    public abstract JsonDeHandle readField(final JsonDeHandle handle);

    /**
     * 读取属性值，通常是字符串或者数值
     *
     * @return
     */
    public abstract char[] readValue();

    /**
     * 读取一个int
     *
     * @return
     */
    public abstract int readInt();

    /**
     * 读取一个long
     *
     * @return
     */
    public abstract long readLong();

    /**
     * 读取字符串， 必须是"或者'包围的字符串值
     *
     * @return
     */
    public abstract String readString();
}
